package com.koutao.stguava.concurrence;

import com.google.common.util.concurrent.*;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.units.qual.C;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;

/**
 * Author:   koutao(301601)
 * Date:     2020/9/17 19:02
 * Description: TODO
 */
public class ListenableFutureDemo {

    /**
     * 泡茶的步骤
     * 1 洗茶壶洗茶杯 2m
     * 2 洗茶叶 1m
     * 3 烧水 4m
     * 4 泡茶 2m
     *
     * @param args
     */

    public static void main(String[] args) {
        long begin = System.currentTimeMillis();
        ListenableFutureDemo demo = new ListenableFutureDemo();
        //serial();
        //demo.parallelThread();
        demo.parallelPoolTwo();

        System.out.println("total time " + (System.currentTimeMillis()-begin)/1000);
    }

    public void parallelThread() {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        new Thread(() -> {
            washCup();
            countDownLatch.countDown();
        }).start();
        new Thread(() -> {
            washTea();
            countDownLatch.countDown();
        }).start();
        new Thread(() -> {
            boil();
            countDownLatch.countDown();
        }).start();
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        pourTea();
    }

    public void parallelPoolTwo() {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        executorService.execute(() -> {
            boil();
            try {
                cyclicBarrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }) ;
        executorService.execute(() -> {
            washCup();
            try {
                cyclicBarrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        executorService.execute(() -> {
            washTea();
            try {
                cyclicBarrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        pourTea();
        executorService.shutdown();
    }

    public void parallelPool() {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.execute(() -> {
            boil();
            selfWait(() -> countDownLatch.countDown());
        }) ;
        executorService.execute(() -> {
            washCup();
            selfWait(() -> countDownLatch.countDown());
        });
        executorService.execute(() -> {
            washTea();
            selfWait(() -> countDownLatch.countDown());
        });
        selfWait(() -> countDownLatch.await());
        pourTea();
        executorService.shutdown();
    }

    public void serial() {


        washCup();

        washTea();

        boil();

        pourTea();
    }

    private void washCup() {
        System.out.println("washing cup... ");
        expend(2);
    }

    private void washTea() {
        System.out.println("washing tea...");
        expend(1);
    }

    private void boil() {
        System.out.println("boiling...");
        expend(4);
    }

    private void pourTea() {
        System.out.println("pouring the tea...");
        expend(2);
    }

    private void expend(Integer second) {
        try {
            Thread.sleep(1000*second);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void selfWait(SelfAwait selfAwait) {
        try {
            selfAwait.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
